﻿using BlazorAdmin.Generator.Generators;
using BlazorAdmin.Generator.Models;
using BootstrapBlazor.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.SqlClient;
using System.IO;
using System.IO.Compression;
using System.Threading.Tasks;
/*using Npgsql;
using System.Data.SqlClient;
using MySql.Data.MySqlClient;
using Oracle.ManagedDataAccess.Client;*/

namespace BlazorAdmin.Generator
{
    public partial class CodeGenerator
    {
        private List<SelectedItem> ProviderItems { get; set; }

        private List<SelectedItem> StyleItems { get; set; }

        public List<ConsoleMessageItem> Messages { get; set; } = new();

        private GenerateSetting Setting { get; set; }

        protected override void OnInitialized()
        {
            base.OnInitialized();

            // 注意：路径只能用单斜杠
            Setting = new()
            {
                RootPath = "Upload",
                // 注意：EntityPath 最终生成的命名空间还是 Pangeo.XXXX.Models 后面没有 Entities
                EntityPath = "Pangeo.Admin.Models/Entities",
                InterfacePath = "Pangeo.Admin.Interface",
                ServicePath = "Pangeo.Admin.Services",
                RazorComponentPath = "Pangeo.Admin.Web.Shared/Components",
                RazorModelPath = "Pangeo.Admin.Web.Shared/Models",
                RazorPagePath = "Pangeo.Admin.Web.Shared/Pages",
                DefaultConnectionString = Config.GetConnectionString("BaMgmtDb")
            };

            StyleItems = new() { new("PetaPocoRazor", "PetaPoco & Razor 风格") };
            ProviderItems = new()
            {
                new(EnumDbProvider.MySql.ToString(), EnumDbProvider.MySql.ToString()),
                new(EnumDbProvider.SqlServer.ToString(), EnumDbProvider.SqlServer.ToString()),
                new(EnumDbProvider.Npgsql.ToString(), EnumDbProvider.Npgsql.ToString()),
                new(EnumDbProvider.Oracle.ToString(), EnumDbProvider.Oracle.ToString())
            };
        }

        Task OnRootPathChanged(string appName)
        {
            if (!string.IsNullOrEmpty(appName))
            {
                string[] arr;
                string oldPrefix = null, newPrefix = null;
                appName = appName.Trim();

                if (!string.IsNullOrEmpty(Setting.EntityPath))
                {
                    arr = Setting.EntityPath.Split(".", StringSplitOptions.RemoveEmptyEntries);
                    if (arr.Length > 1)
                    {
                        oldPrefix = $"{arr[0]}.{arr[1]}.";
                        newPrefix = $"{arr[0]}.{appName}.";
                    }
                }

                if (!string.IsNullOrEmpty(oldPrefix) && !string.IsNullOrEmpty(newPrefix))
                {
                    Setting.EntityPath = Setting.EntityPath.Replace(oldPrefix, newPrefix);
                    Setting.InterfacePath = Setting.InterfacePath.Replace(oldPrefix, newPrefix);
                    Setting.ServicePath = Setting.ServicePath.Replace(oldPrefix, newPrefix);
                    Setting.RazorComponentPath = Setting.RazorComponentPath.Replace(oldPrefix, newPrefix);
                    Setting.RazorModelPath = Setting.RazorModelPath.Replace(oldPrefix, newPrefix);
                    Setting.RazorPagePath = Setting.RazorPagePath.Replace(oldPrefix, newPrefix);
                }
            }

            return Task.CompletedTask;
        }

        public Func<string, Color?, Task> ConsoleAsync { get; set; }

        public CodeGenerator()
        {
            ConsoleAsync = ConsoleAsyncFn;
        }

        public async Task ConsoleAsyncFn(string message, Color? color = null)
        {
            Messages.Add(new() { Message = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}: {message}", Color = color ?? Color.None });

            await InvokeAsync(StateHasChanged);
        }

        async Task GenerateCode(EditContext context)
        {
            if (string.IsNullOrWhiteSpace(Setting.GenTableNames))
            {
                await MsgService.Show(new()
                {
                    Icon = "fa-solid fa-circle-info",
                    Content = "请输入表名，多个用英文逗号,隔开",
                    Color = Color.Danger
                });

                return;
            }
            Setting.GenTableNames = Setting.GenTableNames.Replace("，", ",");

            var generator = new PetaPocoRazorStyleCodes();

            DbProviderFactories.RegisterFactory(EnumDbProvider.SqlServer.ToString(), SqlClientFactory.Instance);
            /*if (Setting.ProviderName == EnumDbProvider.Npgsql.ToString())
                DbProviderFactories.RegisterFactory(EnumDbProvider.Npgsql.ToString(), NpgsqlFactory.Instance);
            else if (Setting.ProviderName == EnumDbProvider.MySql.ToString())
                DbProviderFactories.RegisterFactory(EnumDbProvider.MySql.ToString(), MySqlClientFactory.Instance);
            else if (Setting.ProviderName == EnumDbProvider.Oracle.ToString())
                DbProviderFactories.RegisterFactory(EnumDbProvider.Oracle.ToString(), OracleClientFactory.Instance);
            else
                DbProviderFactories.RegisterFactory(EnumDbProvider.SqlServer.ToString(), SqlClientFactory.Instance);*/

            var errMsg = await generator.RunAsync(Setting, ConsoleAsync);

            if (string.IsNullOrEmpty(errMsg))
            {
                await ConsoleAsync("All Tables Generate Code Success !", Color.Success);

                var fileName = $"Codes_{DateTime.Now.ToString("HH.mm.ss")}.zip";
                var timeFilePath = AppDomain.CurrentDomain.BaseDirectory + Setting.TimePath;
                var zipfilePath = $"{timeFilePath}//{fileName}";

                ZipFile.CreateFromDirectory(Setting.RootFilePath.Replace("\\", "/"), zipfilePath.Replace("\\", "/"));

                await ConsoleAsync($"Create {fileName} Success. Begin Downloading ...", Color.Success);

                if (File.Exists(zipfilePath))
                {
                    using (var stream = new FileStream(zipfilePath.Replace("\\", "/"), FileMode.Open))
                        await DownloadService.DownloadFromStreamAsync(fileName, stream);

                    Directory.Delete(timeFilePath, true);

                    await ConsoleAsync($"Delete Code Folder {Setting.TimePath} Success", Color.Success);

                    await ConsoleAsync($"{Setting.GenTableCount} Table Generate Code Success. Pogram Run End.", Color.Light);
                }
                else
                {
                    await ConsoleAsync($"Generate Error: Can Not Find {zipfilePath} File", Color.Danger);
                }
            }
            else
            {
                await ConsoleAsync($"Generate Error:\n{errMsg}", Color.Danger);
            }
        }

        [Inject]
        private IConfiguration? Config { get; set; }

        [Inject]
        private DownloadService? DownloadService { get; set; }

        [Inject]
        private MessageService? MsgService { get; set; }
    }
}
